#include "sudokucell.h"
#include <QPainter>


namespace sudoku_ui
{
    /**
     * @brief SudokuCell::g_colors  数独单元格显示1~9的颜色
     */
    std::map<int, QColor> SudokuCell::g_colors;

    /**
     * @brief SudokuCell::m_selectedColor   数独单元格被选中颜色
     */
    QColor SudokuCell::g_selectedColor = QColor::fromRgb(216, 191, 216);

    /**
     * @brief SudokuCell::g_defaultColor 默认颜色值
     */
    QColor SudokuCell::g_defaultColor = QColor::fromRgb(75, 0, 130);

    /**
     * @brief SudokuCell::g_backColor   背景颜色
     */
    QColor SudokuCell::g_backColor = Qt::transparent; //QColor::fromRgb(255, 240, 245);

    /**
     * @brief SudokuCell::g_sameColor
     */
    QColor SudokuCell::g_sameColor = QColor::fromRgb(224, 255, 255);

    SudokuCell::SudokuCell(QWidget *parent)
        : QWidget{parent}
    {
        m_values = std::vector<int>(9, 0);
    }

    SudokuCell::SudokuCell(int index, QWidget *parent)
        : QWidget(parent)
        , m_index(index)
    {
        m_values = std::vector<int>(9, 0);
    }

    SudokuCell::SudokuCell(int row, int col, QWidget *parent)
        : QWidget{parent}
        , m_row{row}
        , m_col{col}
    {
        m_values = std::vector<int>(9, 0);
    }

    SudokuCell::~SudokuCell()
    {

    }

    void SudokuCell::setValue(int value)
    {
        if (m_fixed)    // 如果m_fixed为真，则该单元格不能被修改
            return;

        if (this->m_value != 0)
        {
            if (value == 0)
            {
                SudokuCellSignals::removeSudokuCell(this->m_value, this);
                // 发送信号，告知
                this->m_value = 0;
                update();
            }
        }
        else if (this->m_value != value)
        {            
            this->m_value = value;
            SudokuCellSignals::appendSudokuCell(this->m_value, this);
            SudokuCellSignals::checkGame(this->m_row, this->col(), value);
            update();
        }
    }

    int SudokuCell::value() const
    {
        return this->m_value;
    }

    int SudokuCell::index() const
    {
        return this->m_index;
    }

    int SudokuCell::row() const
    {
        return this->m_row;
    }

    int SudokuCell::col() const
    {
        return this->m_col;
    }

    void SudokuCell::updateValue(int value)
    {
        if (m_value > 0)
            return;

        for (auto it = this->m_values.begin(); it != this->m_values.end(); it++)
        {
            if (*it == value)
            {
                this->m_values.erase(it);
                update();
                return;
            }
        }
        this->m_values.push_back(value);
        update();
    }

    void SudokuCell::clearHintValue()
    {
        this->m_values = std::vector<int>(9, 0);
    }

    void SudokuCell::setSame(bool flag)
    {
        if (this->m_same != flag)
        {
            this->m_same = flag;
            update();
        }
    }

    void SudokuCell::setFixed(bool fixed)
    {
        this->m_fixed = fixed;
    }

    void SudokuCell::setBackColor(const QColor &color)
    {
        if (SudokuCell::g_backColor != color)
        {
            SudokuCell::g_backColor = color;
        }
    }

    const QColor &SudokuCell::backColor()
    {
        return SudokuCell::g_backColor;
    }

    void SudokuCell::globalInitColors()
    {
        SudokuCell::globalSetColor(1, QColor::fromRgb(156, 102, 31));
        SudokuCell::globalSetColor(2, QColor::fromRgb(139, 0, 139));
        SudokuCell::globalSetColor(3, QColor::fromRgb(61, 89, 171));
        SudokuCell::globalSetColor(4, QColor::fromRgb(237, 145, 33));
        SudokuCell::globalSetColor(5, QColor::fromRgb(163, 148, 128));
        SudokuCell::globalSetColor(6, QColor::fromRgb(75, 0, 130));
        SudokuCell::globalSetColor(7, QColor::fromRgb(176, 23, 31));
        SudokuCell::globalSetColor(8, QColor::fromRgb(51, 161, 201));
        SudokuCell::globalSetColor(9, QColor::fromRgb(255, 127, 80));
    }

    void SudokuCell::globalSetColor(int value, const QColor &color)
    {
        SudokuCell::g_colors[value] = color;
    }

    const QColor &SudokuCell::globalColor(int value)
    {
        if (SudokuCell::g_colors.count(value) == 0)
            return SudokuCell::g_defaultColor;
        return SudokuCell::g_colors[value];
    }

    void SudokuCell::globalSetSelectedColor(const QColor &color)
    {
        if (SudokuCell::g_selectedColor != color)
        {
            SudokuCell::g_selectedColor = color;
        }
    }

    const QColor &SudokuCell::globalSelectedColor()
    {
        return SudokuCell::g_selectedColor;
    }

    void SudokuCell::globalSetDefaultColor(const QColor &color)
    {
        if (SudokuCell::g_defaultColor != color)
        {
            SudokuCell::g_defaultColor = color;
        }
    }

    const QColor &SudokuCell::globalDefaultColor()
    {
        return SudokuCell::g_defaultColor;
    } 

    void SudokuCell::mousePressEvent(QMouseEvent *event)
    {
        Q_UNUSED(event)
        if (this->m_mouseClicked == false)
        {
            this->m_mouseClicked = true;
            SudokuCellSignals::selectedSudokuCell(this);
            update();
        }
    }

    void SudokuCell::enterEvent(QEvent *event)
    {
        Q_UNUSED(event)
        this->m_focus = true;
        update();
    }

    void SudokuCell::leaveEvent(QEvent *event)
    {
        Q_UNUSED(event)
        this->m_focus = false;
        update();
    }

    void SudokuCell::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event)
        QPainter painter(this);
        painter.setRenderHint(QPainter::TextAntialiasing);

        if (m_same)
            painter.fillRect(rect(), SudokuCell::g_sameColor);
        else if (m_focus || m_mouseClicked)
            painter.fillRect(rect(), SudokuCell::g_selectedColor);
        else
            painter.fillRect(rect(), SudokuCell::g_backColor);

        auto w = this->width();
        auto h = this->height();
        auto f = QFont("Times New Roman");
        auto fs = std::min(w, h) * 3 / 4;
        if (this->m_value > 0 && this->m_value < 10)
        {
            f.setPixelSize(fs);
            painter.setFont(f);
            painter.setPen(QPen(SudokuCell::g_colors[this->m_value]));
            painter.drawText(rect(), Qt::AlignCenter, QString::number(this->m_value));
        }
        else
        {
            f.setPixelSize(fs / 3);
            painter.setFont(f);
            auto w1 = w / 3.f;
            auto h1 = h / 3.f;
            for (const auto& value : this->m_values)
            {
                painter.setPen(QPen(SudokuCell::g_colors[value]));
                int i = (value - 1) / 3;
                int j = (value - 1) % 3;
                auto r = QRectF(w1 * j, h1 * i, w1, h1);
                painter.drawText(r, Qt::AlignCenter, QString::number(value));
            }
        }
    }

    void SudokuCell::resizeEvent(QResizeEvent *event)
    {
        Q_UNUSED(event)
        update();
    }

    void SudokuCell::unSelect()
    {
        if (this->m_mouseClicked)
        {
            this->m_mouseClicked = false;
            update();
        }
    }
}


